#include <iostream>
#include <functional>
#include <memory>
#include "request.pb.h"
#include "muduo/proto/codec.h"
#include "muduo/proto/dispatcher_lite.h"
#include "muduo/proto/dispatcher.h"
#include "muduo/net/EventLoop.h"
#include "muduo/net/TcpServer.h"
using namespace std;


class ProtoServer
{
    typedef shared_ptr<request::TranslateRequest> TranslateRequestPtr;
    typedef shared_ptr<request::TranslateResponse> TranslateResponsePtr;
    typedef shared_ptr<request::CalculatorRequest> CalculatorRequestPtr;
    typedef shared_ptr<request::CalculatorResponse> CalculatorResponsePtr;
public:
    ProtoServer(int port)
    	: _server(&_baseloop, muduo::net::InetAddress(port), "ProtoServer", muduo::net::TcpServer::kReusePort)
	    , _dispatcher(bind(&ProtoServer::onUnknownMessage, this, 
            placeholders::_1, placeholders::_2, placeholders::_3))
	    , _codec(bind(&ProtobufDispatcher::onProtobufMessage, &_dispatcher, 
            placeholders::_1, placeholders::_2, placeholders::_3))
    {
        //注册业务处理函数
        _dispatcher.registerMessageCallback<request::TranslateRequest>(std::bind(&ProtoServer::onTranslate, this,
            placeholders::_1, placeholders::_2, placeholders::_3));
        _dispatcher.registerMessageCallback<request::CalculatorRequest>(std::bind(&ProtoServer::onCalculator, this,
            placeholders::_1, placeholders::_2, placeholders::_3));
        //设置回调函数
        _server.setConnectionCallback(bind(&ProtoServer::onConnection, this, placeholders::_1));
        _server.setMessageCallback(bind(&ProtobufCodec::onMessage, &_codec, placeholders::_1, placeholders::_2, placeholders::_3));
    }

    void start()
    {
        _server.start();
        _baseloop.loop();
    }
    
private:
    string translate(const string& word)
    {
        static unordered_map<string, string> dict = {
            {"sun", "太阳"},
            {"left", "左"},
            {"right", "右"},
            {"hello", "你好"}
        };
        
        auto it = dict.find(word);
        if (it != dict.end())
            return it->second;
        else  
            return "未找到";
    }

    void onTranslate(const muduo::net::TcpConnectionPtr& conn, const TranslateRequestPtr& req, muduo::Timestamp rt)
    {
        //读取请求字符串
        string word = req->word();
        //将请求字符串进行翻译
        string tranStr = translate(word);
        //构建TranslateResponse响应
        request::TranslateResponse resp;
        resp.set_result(tranStr);
        //发送响应
        _codec.send(conn, resp);
    }

    void onCalculator(const muduo::net::TcpConnectionPtr& conn, const CalculatorRequestPtr& req, muduo::Timestamp rt)
    {
        int num1 = req->num1();
        int num2 = req->num2();
        char op = req->op()[0];

        request::CalculatorResponse resp;
        switch(op)
        {
            case '+':
                resp.set_result(num1 + num2);
                resp.set_code(true);
                break;
            case '-':
                resp.set_result(num1 - num2);
                resp.set_code(true);
                break;
            case '*':
                resp.set_result(num1 * num2);
                resp.set_code(true);
                break;
            case '/':
                if (num2 == 0)
                {
                    resp.set_code(false);
                }
                else 
                {
                    resp.set_result(num1 / num2);
                    resp.set_code(true);
                }
                break;                                
        }

        _codec.send(conn, resp);
    }

    void onConnection(const muduo::net::TcpConnectionPtr& conn)
    {
        if (conn->connected())
        {
            cout << "连接成功！！！" << endl;
        }
        else 
        {
            cout << "断开连接" << endl;
        }
    }

    void onUnknownMessage(const muduo::net::TcpConnectionPtr& conn, const MessagePtr& message, muduo::Timestamp)
    {
        std::cout << "onUnknownMessage: " << message->GetTypeName() << std::endl;
    }
    
private:
    muduo::net::EventLoop _baseloop;
    muduo::net::TcpServer _server;
    ProtobufDispatcher _dispatcher;
    ProtobufCodec _codec;
};

int main()
{
    ProtoServer server(8080);
    server.start();

    return 0;
}
